'''
Created on Nov 17, 2011

@author: ctester
'''
import re
import time
import logging
from appscript import *
import appscript
import hmlme


class Util(object):
    @classmethod
    def match(cls, pattern, string):
        return re.match(pattern, string) != None
    
    @classmethod
    def contain(cls, pattern, string):
        return re.search(pattern, string) != None
    
    
class Instruments(object):
    def __init__(self):
        self.name = 'Instruments'
#        self.sys = app('System Events')
#        self.sys = None
#        self.app = app(self.name)
        
    def getApp(self):
        return app(self.name)
    
    def getProc(self):
#        self.sys = app('System Events')
        proc = app('System Events').processes[self.name]
        if proc.exists():
            return proc
        else:
            return None
    
    def getTag(self, ele):
        if appscript.reference.Reference == ele.__class__:
            return ele
        
        proc = self.getProc()
        tag = eval(str(proc) + '.' + ele)    
           
        if tag == None:
            return None
        
        if tag.exists():
            return tag
        else:
            return None
            
    def resolveTarget(self, tag):
        if appscript.reference.Reference == tag.__class__:
            return tag
        
        proc = self.getProc()
        if proc == None:
            print 'target not found: process not found'
            return None

        proc = str(proc)
        old = ''
        
        patn = re.compile(r'\[([^.]+)\]')
        pidx = re.compile(r'([0-9]+|x)(([\+\-\*\/])([0-9]+|x))*', re.I)
        
        while True:
            m1 = patn.search(tag)
            if m1 == None:
                break
            
            s = m1.start()
            e = m1.end()
            
            sidx = m1.group(1)
            
            pfix = tag[:s]
            
#            print old + pfix, ' - pfix'
#            print tag[e:], ' - sfix'
            
            objs = self.getTag(old + pfix)
            if objs == None:
                return None
#            print objs
            cnt = int(objs.count())
#            print 'cnt:', cnt

            m2 = pidx.match(sidx)
            
            if m2 == None:
                ppp = re.compile(sidx[1:len(sidx) - 1])
                found = False
                for i in range(cnt):
#                    title = objs[i].title()
                    title = self.getAttr(objs.get()[i], 'AXTitle')
                    if None == title:
                        continue
#                    print 'title', title, sidx[1:len(sidx) - 1]
                    mmm = ppp.match(title)
                    if mmm != None:
                        if re.compile(r'[^\x00-\x7f]').search(title) != None:
                            old += pfix + '[' + str(i + 1) + ']'
                        else:
                            old += pfix + '[' + sidx[0] + title + sidx[len(sidx) - 1] + ']'
                        tag = tag[e:]
                        found = True
                        break
                if False == found:
                    return None
            else:
                sidx = sidx.lower().replace('x', str(cnt))
                old += pfix + '[' + str(eval(sidx)) + ']'
                tag = tag[e:]
                
        if len(tag) != 0:
            old += tag
        
        tags = eval(proc + '.' + old)
        return tags
    
    def getChildren(self, tag):
        children = []
        ptn = re.compile(r'\[\*\]')
        m = ptn.search(tag)
        
        if m == None:
            _tags = self.resolveTarget(tag)
            if _tags == None:
                return None
            for _t in _tags.get():
                children.append(_t)
        else:
            s = m.start()
            e = m.end()
            
            pfix = tag[:s]
            sfix = tag[e:]
            
            _tags = self.resolveTarget(pfix)
            if _tags == None:
                return None
            
            for _t in _tags.get():
                try:
                    chl = eval(str(_t) + sfix)
                    children.append(chl)
                except:
                    pass
                
        return children
        
    def getChildrenWithAttri(self, tag, attr, value):
        children = self.getChildren(tag)
        for chl in children:
            try:
                _attr = self.getAttr(chl, attr)
                if _attr == value:
                    return chl
            except:
                pass
        return None
#        ptn = re.compile(r'\[\*\]')
#        m = ptn.search(tag)
#        if m == None:
#            return None
#        
#        s = m.start()
#        e = m.end()
#        
#        pfix = tag[:s]
#        sfix = tag[e:]
#        
#        _tags = self.resolveTarget(pfix)
#        if _tags == None:
#            return None
#        
#        for _t in _tags.get():
#            try:
#                chl = eval(str(_t) + sfix)
#                _attr = self.getAttr(chl, attr)
#                if _attr == value:
#                    return chl
#            except:
#                pass
#            
#        return None
        
    def close(self):
        proc = self.getProc()
        if proc != None:
            try:
                self.getApp().quit()
            except:
                pass
        else:
            print 'no process found to quit'
        time.sleep(1)
            
    def launch(self):
        proc = self.getProc()
        if proc == None:
#            self.getApp().launch()
            self.getApp().activate()
        else:
            print 'already launched'
#        self.app.activate()
        
    def setFrontMost(self):
        proc = self.getProc()
        if proc == None:
            print 'Instruments process not found'
        else:
            if True != proc.frontmost.get():
                proc.frontmost.set(True)
            else:
                print 'already front most'
            print proc.frontmost.get()
                
    def click(self, ele):
#        tag = self.getTag(ele)
        tag = self.resolveTarget(ele)
        if tag == None:
            print 'click: tag not found -', ele
            return None
        
        pos = tag.position.get()
        size = tag.size.get()
        
        x = pos[0] + size[0] / 2
        y = pos[1] + size[1] / 2
        
        hmlme.click(x, y)
        time.sleep(1)
    
    def dbClick(self, ele):
        tag = self.resolveTarget(ele)
        if tag == None:
            print 'dbclick: tag not found -', ele
            return None
        
        pos = tag.position.get()
        size = tag.size.get()
        
        x = pos[0] + size[0] / 2
        y = pos[1] + size[1] / 2
        
        hmlme.dbclick(x, y)
        time.sleep(1)
        
    def getAttr(self, _tag, attr):
        tag = self.resolveTarget(_tag)
        
        if tag == None:
            print 'get attr - tag none -', _tag
            return None
        
        # return eval(str(tag) + '.' + attr + '.get()')
        val = None
        try:
            val = tag.attributes[attr].value.get()
        except:
            val = None  
        return val
    
    def keystroke(self, __kk__):
        if __kk__ == None or len(__kk__) == 0:
            return None
        
        dict = {'command': k.command_down, 'option': k.option_down, 
                'control': k.control_down, 'shift': k.shift_down}
        keys = re.compile(r'(?<!\\)\+').split(__kk__)
        
        _using = []
        _keys = []
        
        for i in range(len(keys)):
            _k = keys[i]
            _k = _k.replace(r'\+', r'+')
            _k = _k.replace(r'\\', '\\')

            if dict.get(_k) != None:
                _using.append(dict.get(_k))
            else:
                _keys.append(_k)
        
        if len(_keys) == 0:
            print 'empty key input'
            return None
        
        for _k in _keys:
            isKeyCode = False
            try:
                int(_k)
                isKeyCode = True
            except:
                pass
            
            if len(_using) == 0:
                if isKeyCode == True:
                    app('System Events').key_code(int(_k))
                else:
                    app('System Events').keystroke(_k)
            else:
                if isKeyCode == True:
                    app('System Events').key_code(int(_k), using=_using)
                else:
                    app('System Events').keystroke(_k, using=_using)
            time.sleep(0.2)
        
        
#    def keyCode(self, code):
#        app('System Events').key_code(int(code))

    def waitTillExists(self, _tag):
        tag = None
        t = 0
        while tag == None and t < 20:
            tag = self.resolveTarget(_tag)
            t = t + 1
            time.sleep(1)
        
        if t == 20:
            return False
        else:
            return True